/***********************************************************************************
**  
* @copyright (c) 2010-2019,  Technology Co., LTD. All Right Reserved.
*
************************************************************************************/
/**
* @file	    duye_file_monitor.h
* @version     
* @brief      
* @author
* @date	    2013-03-30
* @note 
*
* 1. 2013-03-30 Created this file
*/

#pragma once

#include <map>
#include <set>
#include <duye_type.h>
#include <duye_system.h>

namespace duye {

class FileMonitorIf {
public:
	virtual ~FileMonitorIf() {}
	
	/* 
	 * @brief callback
	 * @param [in] path : file or directory path
	 * @param [in] event : file event type, list:
	    IN_ACCESS               文件被访问
        IN_ATTRIB               文件属性被修改（比如，权限，所有权，链接计数，扩展属性，用户ID，或组ID等, chmod、chown、touch）
        IN_CLOSE_WRITE          关闭为了写入而打开的文件, close
        IN_CLOSE_NOWRITE        关闭没有写入而打开的文件
        IN_CREATE               在受监控目录下创建了文件或目录
        IN_DELETE               在受监控目录内删除了文件或目录, rm
        IN_DELETE_SELF          自删除，即一个可执行文件在执行时删除自己
        IN_MODIFY               文件被修改
        IN_MOVE_SELF            自移动，即一个可执行文件在执行时移动自己
        IN_MOVED_FROM           文件被移走, 如mv
        IN_MOVED_TO             文件被移来，如mv、cp
        IN_OPEN                 文件被打开
        IN_UNMOUNT              宿主文件系统被 umount
        IN_MORE_SELF            重命名对象时会发生事件
     * @param [in] is_dir : is directory
     */	
	virtual bool onFileChangeNotify(const std::string& path, const uint32& event, const bool& is_dir) = 0;
};

class FileMonitor : public duye::ThreadTask {
private:
	typedef std::map<uint32, std::string> EventDescMap;

	class FileEvent {
	public: 
		FileEvent(const uint32& _event, const bool& _is_dir, const std::string& _path) 
			: event(_event), is_dir(_is_dir), path(_path) {}

		uint32 event;
		bool is_dir;
		std::string path;
	};	

public:
	FileMonitor();
	~FileMonitor();

	bool start();
	bool stop();

	bool setMonitor(FileMonitorIf* monitor);
	bool includePath(const std::string& path);
	bool includePath(const std::list<std::string>& path_list);
	bool excludePath(const std::string& path);
	bool excludePath(const std::list<std::string>& path_list);

private:
	// imple duye::ThreadTask
	virtual bool run();
	bool addWatchFile();
	void printLog(const uint32 event, int8* path, const bool is_dir);

private:
	FileMonitorIf* m_monitor;
	std::set<std::string> m_in_path_set;
	std::set<std::string> m_ex_path_set;
	
	bool m_stoped;
	Condition m_stop_cond;
	Epoll m_epoll;

	Inotify m_inotify;
	int32 m_notify_fd;

	EventDescMap m_event_desc_map;
};

}
